home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / mthrowu.c < prev    next >
C/C++ Source or Header  |  1992-12-07  |  15KB  |  582 lines

  1. /*    SCCS Id: @(#)mthrowu.c    3.1    92/11/14    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include    "hack.h"
  6.  
  7. STATIC_DCL void FDECL(drop_throw,(struct obj *,BOOLEAN_P,int,int));
  8. #ifndef MUSE
  9. STATIC_DCL void FDECL(m_throw,(struct monst *,int,int,int,int,int,struct obj *));
  10. #endif
  11.  
  12. #define URETREATING(x,y) (distmin(u.ux,u.uy,x,y) > distmin(u.ux0,u.uy0,x,y))
  13.  
  14. boolean FDECL(lined_up, (struct monst *));
  15.  
  16. #ifndef OVLB
  17.  
  18. STATIC_DCL const char *breathwep[];
  19.  
  20. #else /* OVLB */
  21.  
  22. /*
  23.  * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
  24.  */
  25. STATIC_OVL const char NEARDATA *breathwep[] = {
  26.                 "fragments",
  27.                 "fire",
  28.                 "frost",
  29.                 "sleep gas",
  30.                 "death",
  31.                 "lightning",
  32.                 "poison gas",
  33.                 "acid",
  34.                 "strange breath #8",
  35.                 "strange breath #9"
  36. };
  37.  
  38. int
  39. thitu(tlev, dam, obj, name)    /* u is hit by sth, but not a monster */
  40.     register int tlev, dam;
  41.     struct obj *obj;
  42.     register const char *name;
  43. {
  44.     const char *onm = (obj && obj_is_pname(obj)) ? the(name) : an(name);
  45.     boolean is_acid = (obj && obj->otyp == ACID_VENOM);
  46.  
  47.     if(u.uac + tlev <= rnd(20)) {
  48.         if(Blind || !flags.verbose) pline("It misses.");
  49.         else You("are almost hit by %s!", onm);
  50.         return(0);
  51.     } else {
  52.         if(Blind || !flags.verbose) You("are hit!");
  53.         else You("are hit by %s!", onm);
  54. #ifdef POLYSELF
  55.         if (obj && objects[obj->otyp].oc_material == SILVER
  56.                 && hates_silver(uasmon)) {
  57.             dam += rnd(20);
  58.             pline("The silver sears your flesh!");
  59.             exercise(A_CON, FALSE);
  60.         }
  61.         if (is_acid && resists_acid(uasmon))
  62.             pline("It doesn't seem to hurt you.");
  63.         else {
  64. #endif
  65.             if (is_acid) pline("It burns!");
  66.             if (Half_physical_damage) dam = (dam+1) / 2;
  67.             losehp(dam, name, (obj && obj_is_pname(obj)) ?
  68.                    KILLED_BY : KILLED_BY_AN);
  69.             exercise(A_STR, FALSE);
  70. #ifdef POLYSELF
  71.         }
  72. #endif
  73.         return(1);
  74.     }
  75. }
  76.  
  77. /* Be sure this corresponds with what happens to player-thrown objects in
  78.  * dothrow.c (for consistency). --KAA
  79.  */
  80.  
  81. STATIC_OVL void
  82. drop_throw(obj, ohit, x, y)
  83. register struct obj *obj;
  84. boolean ohit;
  85. int x,y;
  86. {
  87.     int create;
  88.     struct monst *mtmp;
  89.     struct trap *t;
  90.  
  91.     if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS)
  92.         create = 0;
  93.     else if (ohit &&
  94.          ((obj->otyp >= ARROW && obj->otyp <= SHURIKEN) ||
  95.           obj->otyp == ROCK))
  96.         create = !rn2(3);
  97.     else create = 1;
  98.     if (create && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && 
  99.             (t = t_at(x, y)) && ((t->ttyp == PIT) || 
  100.             (t->ttyp == SPIKED_PIT))) && 
  101.         !flooreffects(obj,x,y,"fall")) { /* don't double-dip on damage */
  102.         place_object(obj, x, y);
  103.         obj->nobj = fobj;
  104.         fobj = obj;
  105.         stackobj(fobj);
  106.     } else obfree(obj, (struct obj*) 0);
  107. }
  108.  
  109. #endif /* OVLB */
  110. #ifdef OVL1
  111.  
  112. #ifndef MUSE
  113. STATIC_OVL
  114. #endif
  115. void
  116. m_throw(mon, x, y, dx, dy, range, obj)
  117.     register struct monst *mon;
  118.     register int x,y,dx,dy,range;        /* direction and range */
  119.     register struct obj *obj;
  120. {
  121.     register struct monst *mtmp;
  122.     struct obj *singleobj;
  123.     char sym = obj->oclass;
  124.     int damage;
  125.     int hitu, blindinc=0;
  126.  
  127.     bhitpos.x = x;
  128.     bhitpos.y = y;
  129.  
  130.     singleobj = splitobj(obj, obj->quan - 1L);
  131.     /* splitobj leaves the new object in the chain (i.e. the monster's
  132.      * inventory).  Remove it.  We can do this in 1 line, but it's highly
  133.      * dependent on the fact that we know splitobj() places it immediately
  134.      * after obj.
  135.      */
  136.     obj->nobj = singleobj->nobj;
  137.     /* Get rid of object.  This cannot be done later on; what if the
  138.      * player dies before then, leaving the monster with 0 daggers?
  139.      * (This caused the infamous 2^32-1 orcish dagger bug).
  140.      */
  141.     if (!obj->quan) {
  142.         if(obj->oclass == VENOM_CLASS) {
  143.         /* venom is not in the monster's inventory chain */
  144.         dealloc_obj(obj);
  145.         } else {
  146. #ifdef MUSE
  147.         /* not possibly_unwield, which checks the object's */
  148.         /* location, not its existence */
  149.         if (MON_WEP(mon) == obj)
  150.             MON_NOWEP(mon);
  151. #endif
  152.         m_useup(mon, obj);
  153.         }
  154.     }
  155.  
  156.     if (singleobj->cursed && (dx || dy) && !rn2(7)) {
  157.         if(canseemon(mon) && flags.verbose) {
  158.         if((singleobj->oclass == WEAPON_CLASS ||
  159.                         singleobj->oclass == GEM_CLASS)
  160.            && objects[singleobj->otyp].w_propellor)
  161.             pline("%s misfires!", Monnam(mon));
  162.         else
  163.             pline("The %s slips as %s throws it!",
  164.               xname(singleobj), mon_nam(mon));
  165.         }
  166.         dx = rn2(3)-1;
  167.         dy = rn2(3)-1;
  168.         /* pre-check validity of new direction */
  169.         if((!dx && !dy)
  170.            || !isok(bhitpos.x+dx,bhitpos.y+dy)
  171.            /* missile hits the wall */
  172.            || IS_WALL(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
  173.            || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SDOOR
  174.            || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SCORR) {
  175.         drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
  176.         return;
  177.         }
  178.     }
  179.  
  180.     /* Note: drop_throw may destroy singleobj.  Since obj must be destroyed
  181.      * early to avoid the dagger bug, anyone who modifies this code should
  182.      * be careful not to use either one after it's been freed.
  183.      */
  184.     if (sym) tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
  185.     while(range-- > 0) { /* Actually the loop is always exited by break */
  186.         boolean vis;
  187.  
  188.         bhitpos.x += dx;
  189.         bhitpos.y += dy;
  190.         vis = cansee(bhitpos.x, bhitpos.y);
  191.         if(MON_AT(bhitpos.x, bhitpos.y)) {
  192.             boolean ismimic;
  193.  
  194.             mtmp = m_at(bhitpos.x,bhitpos.y);
  195.             ismimic = mtmp->m_ap_type &&
  196.             mtmp->m_ap_type != M_AP_MONSTER;
  197.  
  198.             /* don't use distance/size modifiers since target was u */
  199.             if(find_mac(mtmp) + 8 + singleobj->spe <= rnd(20)) {
  200.             if (!ismimic) {
  201.                 if (!vis) pline("It is missed.");
  202.                 else miss(distant_name(singleobj,xname), mtmp);
  203.             }
  204.             if (!range) { /* Last position; object drops */
  205.                 drop_throw(singleobj, 0, mtmp->mx, mtmp->my);
  206.                 break;
  207.             }
  208. #ifdef MUSE
  209.             } else if (singleobj->oclass == POTION_CLASS) {
  210.             if (ismimic) seemimic(mtmp);
  211.             if (vis) singleobj->dknown = 1;
  212.             potionhit(mtmp, singleobj);
  213.             break;
  214. #endif
  215.             } else {
  216.             damage = dmgval(singleobj, mtmp->data);
  217.             if (damage < 1) damage = 1;
  218.             if (singleobj->otyp==ACID_VENOM && resists_acid(mtmp->data))
  219.                 damage = 0;
  220.             if (ismimic) seemimic(mtmp);
  221.             if (!vis) pline("It is hit%s", exclam(damage));
  222.             else hit(distant_name(singleobj,xname),
  223.                             mtmp,exclam(damage));
  224.             if (singleobj->opoisoned) {
  225.                 if (resists_poison(mtmp->data)) {
  226.                 if (vis)
  227.                   pline("The poison doesn't seem to affect %s.",
  228.                                 mon_nam(mtmp));
  229.                 } else {
  230.                 if (rn2(30)) damage += rnd(6);
  231.                 else {
  232.                     if (vis)
  233.                     pline("The poison was deadly...");
  234.                     damage = mtmp->mhp;
  235.                 }
  236.                 }
  237.             }
  238.             if (objects[singleobj->otyp].oc_material == SILVER
  239.                 && hates_silver(mtmp->data)) {
  240.                 if (vis) pline("The silver sears %s's flesh!",
  241.                 mon_nam(mtmp));
  242.                 else pline("Its flesh is seared!");
  243.             }
  244.             if (singleobj->otyp==ACID_VENOM && cansee(mtmp->mx,mtmp->my)){
  245.                 if (resists_acid(mtmp->data)) {
  246.                 pline("%s is unaffected.", vis ? Monnam(mtmp)
  247.                     : "It");
  248.                 damage = 0;
  249.                 } else if (vis)
  250.                 pline("The acid burns %s!", mon_nam(mtmp));
  251.                 else pline("It is burned!");
  252.             }
  253.             mtmp->mhp -= damage;
  254.             if(mtmp->mhp < 1) {
  255.                 pline("%s is %s!", vis ? Monnam(mtmp) : "It",
  256.                    (is_demon(mtmp->data) || 
  257.                     is_undead(mtmp->data) || !vis) ?
  258.                  "destroyed" : "killed");
  259.                 mondied(mtmp);
  260.             }
  261.  
  262.             if(((singleobj->otyp == CREAM_PIE) ||
  263.                 (singleobj->otyp == BLINDING_VENOM))
  264.                && haseyes(mtmp->data)) {
  265.                 if (vis)
  266.                 pline("%s is blinded by %s.",
  267.                       Monnam(mtmp), the(xname(singleobj)));
  268.                 if(mtmp->msleep) mtmp->msleep = 0;
  269.                 mtmp->mcansee = 0;
  270.                 {
  271.                 register unsigned rnd_tmp = rnd(25) + 20;
  272.                 if((mtmp->mblinded + rnd_tmp) > 127)
  273.                     mtmp->mblinded = 127;
  274.                 else mtmp->mblinded += rnd_tmp;
  275.                 }
  276.             }
  277.             drop_throw(singleobj, 1, bhitpos.x, bhitpos.y);
  278.             break;
  279.             }
  280.         }
  281.         if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
  282.             if (multi) nomul(0);
  283.  
  284. #ifdef MUSE
  285.             if (singleobj->oclass == POTION_CLASS) {
  286.                 if (!Blind) singleobj->dknown = 1;
  287.                 potionhit(&youmonst, singleobj);
  288.                 break;
  289.             }
  290. #endif
  291.             switch(singleobj->otyp) {
  292.                 int dam, hitv;
  293.                 case CREAM_PIE:
  294.                 case BLINDING_VENOM:
  295.                 hitu = thitu(8, 0, singleobj, xname(singleobj));
  296.                 break;
  297.                 default:
  298.                 dam = dmgval(singleobj, uasmon);
  299.                 hitv = 3 - distmin(u.ux,u.uy, mon->mx,mon->my);
  300.                 if (hitv < -4) hitv = -4;
  301.                 if (is_elf(mon->data) &&
  302.                     objects[singleobj->otyp].w_propellor
  303.                                 == WP_BOW) {
  304.                     hitv++;
  305. #ifdef MUSE
  306.                     if (MON_WEP(mon) &&
  307.                     MON_WEP(mon)->otyp == ELVEN_BOW)
  308.                     hitv++;
  309. #endif
  310.                     if(singleobj->otyp == ELVEN_ARROW) dam++;
  311.                 }
  312. #ifdef POLYSELF
  313.                 if (bigmonst(uasmon)) hitv++;
  314. #endif
  315.                 hitv += 8+singleobj->spe;
  316.  
  317.                 if (dam < 1) dam = 1;
  318.                 hitu = thitu(hitv, dam,
  319.                     singleobj, xname(singleobj));
  320.             }
  321.             if (hitu && singleobj->opoisoned)
  322.                 /* it's safe to call xname twice because it's the
  323.                    same object both times... */
  324.                 poisoned(xname(singleobj), A_STR, xname(singleobj), 10);
  325.             if(hitu && (singleobj->otyp == CREAM_PIE ||
  326.                      singleobj->otyp == BLINDING_VENOM)) {
  327.                 blindinc = rnd(25);
  328.                 if(singleobj->otyp == CREAM_PIE) {
  329.                 if(!Blind) pline("Yecch!  You've been creamed.");
  330.                 else    pline("There's something sticky all over your %s.", body_part(FACE));
  331.                 } else {    /* venom in the eyes */
  332.                 if(Blindfolded) /* nothing */ ;
  333.                 else if(!Blind) pline("The venom blinds you.");
  334.                 else    Your("%s sting.",
  335.                     makeplural(body_part(EYE)));
  336.                 }
  337.             }
  338.             stop_occupation();
  339.             if (hitu || !range) {
  340.                 drop_throw(singleobj, hitu, u.ux, u.uy);
  341.                 break;
  342.             }
  343.         } else if (!range    /* reached end of path */
  344.             /* missile hits edge of screen */
  345.             || !isok(bhitpos.x+dx,bhitpos.y+dy)
  346.             /* missile hits the wall */
  347.             || IS_WALL(levl[bhitpos.x+dx][bhitpos.y+dy].typ)
  348.             || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SDOOR
  349.             || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SCORR
  350. #ifdef SINKS
  351.             /* Thrown objects "sink" */
  352.             || IS_SINK(levl[bhitpos.x][bhitpos.y].typ)
  353. #endif
  354.                                 ) {
  355.             drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
  356.             break;
  357.         }
  358.         tmp_at(bhitpos.x, bhitpos.y);
  359.         delay_output();
  360.     }
  361.     tmp_at(bhitpos.x, bhitpos.y);
  362.     delay_output();
  363.     tmp_at(DISP_END, 0);
  364.     /* blindfold keeps substances out of your eyes */
  365.     if (blindinc && !Blindfolded) {
  366.         u.ucreamed += blindinc;
  367.         make_blinded(Blinded + blindinc,FALSE);
  368.     }
  369. }
  370.  
  371. #endif /* OVL1 */
  372. #ifdef OVLB
  373.  
  374. /* Remove an item from the monster's inventory.
  375.  */
  376. void
  377. m_useup(mon, obj)
  378. struct monst *mon;
  379. struct obj *obj;
  380. {
  381.     struct obj *otmp, *prev;
  382.  
  383.     if (obj->quan > 1L) {
  384.         obj->quan--;
  385.         return;
  386.     }
  387.     prev = ((struct obj *) 0);
  388.     for (otmp = mon->minvent; otmp; otmp = otmp->nobj) {
  389.         if (otmp == obj) {
  390.             if (prev)
  391.                 prev->nobj = obj->nobj;
  392.             else
  393.                 mon->minvent = obj->nobj;
  394.             dealloc_obj(obj);
  395.             break;
  396.         }
  397.         prev = otmp;
  398.     }
  399. }
  400.  
  401. #endif /* OVLB */
  402. #ifdef OVL1
  403.  
  404. void
  405. thrwmu(mtmp)    /* monster throws item at you */
  406. register struct monst *mtmp;
  407. {
  408.     struct obj *otmp;
  409.     register xchar x, y;
  410.  
  411.     if(lined_up(mtmp)) {
  412. #ifdef MUSE
  413.         if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
  414.         mtmp->weapon_check = NEED_RANGED_WEAPON;
  415.         /* mon_wield_item resets weapon_check as appropriate */
  416.         if(mon_wield_item(mtmp) != 0) return;
  417.         }
  418. #endif
  419.         if((otmp = select_rwep(mtmp))) {
  420.         /* If you are coming toward the monster, the monster
  421.          * should try to soften you up with missiles.  If you are
  422.          * going away, you are probably hurt or running.  Give
  423.          * chase, but if you are getting too far away, throw.
  424.          */
  425.         x = mtmp->mx;
  426.         y = mtmp->my;
  427.         if(!URETREATING(x,y) ||
  428.            !rn2(BOLT_LIM-distmin(x,y,mtmp->mux,mtmp->muy)))
  429.         {
  430.             const char *verb = "throws";
  431.  
  432.             if (otmp->otyp == ARROW
  433.             || otmp->otyp == ELVEN_ARROW
  434.             || otmp->otyp == ORCISH_ARROW
  435.             || otmp->otyp == CROSSBOW_BOLT) verb = "shoots";
  436.             if (canseemon(mtmp)) {
  437.             pline("%s %s %s!", Monnam(mtmp), verb,
  438.                   obj_is_pname(otmp) ?
  439.                   the(singular(otmp, xname)) :
  440.                   an(singular(otmp, xname)));
  441.             }
  442.             m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), 
  443.             distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp);
  444.             nomul(0);
  445.             return;
  446.         }
  447.         }
  448.     }
  449. }
  450.  
  451. #endif /* OVL1 */
  452. #ifdef OVLB
  453.  
  454. int
  455. spitmu(mtmp, mattk)        /* monster spits substance at you */
  456. register struct monst *mtmp;
  457. register struct attack *mattk;
  458. {
  459.     register struct obj *otmp;
  460.  
  461.     if(mtmp->mcan) {
  462.  
  463.         if(flags.soundok)
  464.         pline("A dry rattle comes from %s throat", 
  465.                               s_suffix(mon_nam(mtmp)));
  466.         return 0;
  467.     }
  468.     if(lined_up(mtmp)) {
  469.         switch (mattk->adtyp) {
  470.             case AD_BLND:
  471.             case AD_DRST:
  472.             otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
  473.             break;
  474.             default:
  475.             impossible("bad attack type in spitmu");
  476.                 /* fall through */
  477.             case AD_ACID:
  478.             otmp = mksobj(ACID_VENOM, TRUE, FALSE);
  479.             break;
  480.         }
  481.         if(!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy))) {
  482.             if (canseemon(mtmp))
  483.             pline("%s spits venom!", Monnam(mtmp));
  484.             m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), 
  485.             distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp);
  486.             nomul(0);
  487.             return 0;
  488.         }
  489.     }
  490.     return 0;
  491. }
  492.  
  493. #endif /* OVLB */
  494. #ifdef OVL1
  495.  
  496. int
  497. breamu(mtmp, mattk)            /* monster breathes at you (ranged) */
  498.     register struct monst *mtmp;
  499.     register struct attack  *mattk;
  500. {
  501.     /* if new breath types are added, change AD_ACID to max type */
  502.     int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
  503.  
  504.     if(lined_up(mtmp)) {
  505.  
  506.         if(mtmp->mcan) {
  507.         if(flags.soundok) {
  508.             if(canseemon(mtmp))
  509.             pline("%s coughs.", Monnam(mtmp));
  510.             else
  511.             You("hear a cough.");
  512.         }
  513.         return(0);
  514.         }
  515.         if(!mtmp->mspec_used && rn2(3)) {
  516.  
  517.         if((typ >= AD_MAGM) && (typ <= AD_ACID)) {
  518.  
  519.             if(canseemon(mtmp))
  520.             pline("%s breathes %s!", Monnam(mtmp),
  521.                   breathwep[typ-1]);
  522.             buzz((int) (-20 - (typ-1)), (int)mattk->damn,
  523.              mtmp->mx, mtmp->my, sgn(tbx), sgn(tby));
  524.             nomul(0);
  525.             /* breath runs out sometimes. Also, give monster some
  526.              * cunning; don't breath if the player fell asleep.
  527.              */
  528.             if(!rn2(3))
  529.             mtmp->mspec_used = 10+rn2(20);
  530.             if(typ == AD_SLEE && !Sleep_resistance)
  531.             mtmp->mspec_used += rnd(20);
  532.         } else impossible("Breath weapon %d used", typ-1);
  533.         }
  534.     }
  535.     return(1);
  536. }
  537.  
  538. boolean
  539. linedup(ax, ay, bx, by)
  540. register xchar ax, ay, bx, by;
  541. {
  542.     tbx = ax - bx;    /* These two values are set for use */
  543.     tby = ay - by;    /* after successful return.        */
  544.  
  545.     if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
  546.        && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
  547.  
  548.         if(ax == u.ux && ay == u.uy) return couldsee(bx,by);
  549.         else if(clear_path(ax,ay,bx,by)) return TRUE;
  550.     }
  551.     return FALSE;
  552. }
  553.  
  554. boolean
  555. lined_up(mtmp)        /* is mtmp in position to use ranged attack? */
  556.     register struct monst *mtmp;
  557. {
  558.     return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my));
  559. }
  560.  
  561. #endif /* OVL1 */
  562. #ifdef OVL0
  563.  
  564. /* Check if a monster is carrying a particular item.
  565.  */
  566. struct obj *
  567. m_carrying(mtmp, type)
  568. struct monst *mtmp;
  569. int type;
  570. {
  571.     register struct obj *otmp;
  572.  
  573.     for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
  574.         if(otmp->otyp == type)
  575.             return(otmp);
  576.     return((struct obj *) 0);
  577. }
  578.  
  579. #endif /* OVL0 */
  580.  
  581. /*mthrowu.c*/
  582.